package com.xlh.service.cases.impl;

import cn.hutool.core.util.RandomUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.xlh.dao.cases.BusinessMapper;
import com.xlh.dao.cases.CaseLibraryMapper;
import com.xlh.dao.cases.StarMapper;
import com.xlh.dao.cases.ext.StarMapperExt;
import com.xlh.dto.PageDTO;
import com.xlh.dto.cases.*;
import com.xlh.enums.LocalResourcesEnum;
import com.xlh.enums.SystemConfigEnum;
import com.xlh.enums.cases.JudgeEnum;
import com.xlh.exception.common.BadRequestException;
import com.xlh.exception.common.GlobalException;
import com.xlh.param.cases.BusinessParam;
import com.xlh.param.cases.CreateCaseLibraryParam;
import com.xlh.param.cases.UpdateBusinessParam;
import com.xlh.param.cases.UpdateCaseLibraryParam;
import com.xlh.pojo.cases.*;
import com.xlh.pojo.system.SystemConfig;
import com.xlh.security.UserInfoHolder;
import com.xlh.service.cases.BusinessCaseService;
import com.xlh.service.system.SystemConfigService;
import com.xlh.util.BeanUtil;
import com.xlh.util.FileUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 行业案例
 * <p>
 * Created by lx on 2019/1/28.
 */
@Service
public class BusinessCaseImpl implements BusinessCaseService {

    @Autowired
    private BusinessMapper businessMapper;

    @Autowired
    private CaseLibraryMapper caseLibraryMapper;

    @Autowired
    private StarMapper starMapper;

    @Autowired
    private StarMapperExt starMapperExt;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @Autowired
    private SystemConfigService configService;

    private final static Logger logger = LoggerFactory.getLogger(BusinessCaseImpl.class);

    @Override
    public List<BusinessDTO> listBusiness() {
        // 获取未删除行业数据信息并降序排序
        BusinessExample example = new BusinessExample();
        example.setOrderByClause("id DESC");
        example.createCriteria().andDeletedEqualTo(false);
        List<Business> businesses = businessMapper.selectByExample(example);
        // 转换结果集并获取每个行业的案例数量
        return convertBusiness(businesses);
    }

    @Override
    public void createBusiness(BusinessParam createParam) {
        // 检查参数
        checkCreateBusinessParam(createParam);
        // 转换并插入数据库
        businessMapper.insertSelective(BeanUtil.transform(Business.class, createParam));
    }

    @Override
    public void updateBusiness(UpdateBusinessParam updateParam) {
        // 检查参数
        checkUpdateBusinessParam(updateParam);
        // 转换并修改数据库的值
        Business business = BeanUtil.transform(Business.class, updateParam);
        businessMapper.updateByPrimaryKeySelective(business);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delBusinessCase(Long businessId) {

        checkBusinessIdExist(businessId);

        // 查询案例
        List<CaseLibraryDTO> caseLibraryDTOS = listCase(businessId);

        // 删除行业数据
        Business business = new Business();
        business.setId(businessId);
        business.setDeleted(true);
        businessMapper.updateByPrimaryKeySelective(business);

        if (CollectionUtils.isEmpty(caseLibraryDTOS)) {
            return;
        }

        // 删除案例及点赞数记录
        deleteCase(caseLibraryDTOS.stream().map(CaseLibraryDTO::getId).collect(Collectors.toList()));

    }

    @Override
    public List<CaseLibraryDTO> listCase(Long businessId) {
        // 获取未删除的行业中案例的数据
        CaseLibraryExample example = new CaseLibraryExample();
        example.setOrderByClause("id DESC");
        example.createCriteria().andDeletedEqualTo(false).andBusinessIdEqualTo(businessId);
        List<CaseLibrary> caseLibraries = caseLibraryMapper.selectByExample(example);
        // 转换结果集
        return convertCaseLibrarys(caseLibraries);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createCaseLibrary(CreateCaseLibraryParam createParam) {

        // 检查创建案例参数
        checkCreateCaseLibraryParam(createParam);

        // 转换结果集，若当前端未传图片名事，则随机图片放到对象中
        CaseLibrary caseLibrary = BeanUtil.transform(CaseLibrary.class, createParam);
        convertRandomCaseFile(caseLibrary);

        // 插入案例表中
        caseLibraryMapper.insertSelective(caseLibrary);

    }

    @Override
    public void updateCaseLibrary(UpdateCaseLibraryParam updateParam) {

        // 检查修改案例参数
        checkUpdateCaseLibraryParam(updateParam);

        // 转换结果集，若当前端未传图片名事，则随机图片放到对象中
        CaseLibrary caseLibrary = BeanUtil.transform(CaseLibrary.class, updateParam);
        convertRandomCaseFile(caseLibrary);

        // 插入案例表中
        caseLibraryMapper.updateByPrimaryKeySelective(caseLibrary);
    }

    @Override
    public CaseLibraryDetailDTO getCase(Long id) {
        CaseLibrary caseLibrary = caseLibraryMapper.selectByPrimaryKey(id);
        if (caseLibrary == null || caseLibrary.getDeleted()) {
            throw new BadRequestException("当前案例不存在或已删除");
        }
        return BeanUtil.transform(CaseLibraryDetailDTO.class, caseLibrary);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCase(List<Long> caseIds) {
        // 删除案例
        deleteCases(null, caseIds);
        // 删除点赞数记录
        deleteStar(caseIds);
    }

    @Override
    public List<CasePicDTO> changePic(List<String> base64List) {
        List<CasePicDTO> result = new ArrayList<>();
        base64List.forEach(s -> {
            String fileName = UUID.randomUUID().toString().replace("-", "") + ".png";
            FileUtil.downloadBase64Pic(s, LocalResourcesEnum.CASES.getLocalUploadPath(fileName));
            result.add(new CasePicDTO(fileName, LocalResourcesEnum.CASES.getMappingUrl(fileName)));
        });
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clickStar(JudgeEnum judgeEnum, Long caseId) {
        // 判断参数是否正确，并获取案例表数据
        if (judgeEnum == null) {
            throw new BadRequestException();
        }
        CaseLibraryDetailDTO caseLibraryDetailDTO = getCase(caseId);

        // 修改案例中点赞数量
        updateCaseStar(judgeEnum, caseLibraryDetailDTO);
        // 修改点赞表中的记录
        updateStar(judgeEnum, caseId);
    }

    @Override
    public List<Star> getStarInfoById(Long caseId) {
        StarExample example = new StarExample();
        example.createCriteria()
                .andDeletedEqualTo(false)
                .andStarUserIdEqualTo(userInfoHolder.getUserId())
                .andCaseIdEqualTo(caseId);
        return starMapper.selectByExample(example);
    }

    @Override
    public PageDTO<StarRankDTO> starRankList(Integer pageNum, Integer pageSize, Integer orderStatus) {
        PageHelper.startPage(pageNum, pageSize);
        List<StarRankDTO> starRankList = starMapperExt.getStarRankList(orderStatus);
        PageInfo<StarRankDTO> pageInfo = new PageInfo<>(starRankList);
        return new PageDTO<>(pageInfo);
    }

    /**
     * 转换行业结果集
     *
     * @param businesses 需要转换的数据
     * @return
     */
    private List<BusinessDTO> convertBusiness(List<Business> businesses) {

        // 转换结果集
        List<BusinessDTO> result = BeanUtil.batchTransform(BusinessDTO.class, businesses);

        if (CollectionUtils.isEmpty(result)) return result;

        // 将图标地址赋值
        List<BusinessDTO> businessDTOS = configService.convertIcon(result, LocalResourcesEnum.CASES);

        // 获取所有行业的案例信息
        List<Long> businessIds = businesses.stream().map(Business::getId).collect(Collectors.toList());
        CaseLibraryExample example = new CaseLibraryExample();
        example.createCriteria().andDeletedEqualTo(false).andBusinessIdIn(businessIds);
        List<CaseLibrary> caseLibraries = caseLibraryMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(caseLibraries)) return businessDTOS;

        // 统计案例个数赋值到结果集中
        Map<Long, List<CaseLibrary>> caseLibraryMap = BeanUtil.aggByKeyToList("businessId", caseLibraries);
        businessDTOS.forEach(businessDTO -> {
            List<CaseLibrary> data = caseLibraryMap.get(businessDTO.getId());
            if (CollectionUtils.isNotEmpty(data)) {
                businessDTO.setCaseNum(data.stream().count());
            }
        });
        return businessDTOS;
    }

    /**
     * 检查创建行业参数
     *
     * @param createParam 创建参数
     */
    private void checkCreateBusinessParam(BusinessParam createParam) {

        // 检查行业名称是否存在
        checkBusinessNameExist(null, createParam.getName());

        // 检查图标是否存在
        checkIconExist(createParam.getIcon(), SystemConfigEnum.CASE_ICON);

    }

    /**
     * 检查行业名称是否存在
     *
     * @param id   行业id
     * @param name 名称
     */
    private void checkBusinessNameExist(Long id, String name) {
        BusinessExample example = new BusinessExample();
        BusinessExample.Criteria criteria = example.createCriteria();
        criteria.andNameEqualTo(name);
        criteria.andDeletedEqualTo(false);
        if (id != null) {
            criteria.andIdNotEqualTo(id);
        }
        List<Business> businesses = businessMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(businesses)) {
            throw new BadRequestException("行业案例名称已存在，请重新添加");
        }
    }

    /**
     * 检查图标是否存在
     *
     * @param icon             图标id
     * @param systemConfigEnum 枚举
     */
    private void checkIconExist(Integer icon, SystemConfigEnum systemConfigEnum) {
        List<SystemConfig> systemConfigs = configService.listConfig(
                Lists.newArrayList(icon), systemConfigEnum);
        if (CollectionUtils.isEmpty(systemConfigs)) {
            throw new BadRequestException("图标异常，请刷新页面重新添加");
        }
    }

    /**
     * 检查修改行业参数
     *
     * @param updateParam 修改的参数
     */
    private void checkUpdateBusinessParam(UpdateBusinessParam updateParam) {
        Preconditions.checkNotNull(updateParam);
        // 检查行业id是否存在
        checkBusinessIdExist(updateParam.getId());
        // 检查是否重名
        checkBusinessNameExist(updateParam.getId(), updateParam.getName());

        // 检查图标是否异常
        checkIconExist(updateParam.getIcon(), SystemConfigEnum.CASE_ICON);
    }

    /**
     * 检查行业id是否存在
     *
     * @param id 行业id
     */
    private void checkBusinessIdExist(Long id) {
        Business business = businessMapper.selectByPrimaryKey(id);
        if (business == null || business.getDeleted()) {
            throw new GlobalException("当前行业不存在或已删除");
        }
    }

    /**
     * 转换案例结果集
     *
     * @param data 数据库数据
     * @return
     */
    private List<CaseLibraryDTO> convertCaseLibrarys(List<CaseLibrary> data) {

        if (CollectionUtils.isEmpty(data)) return Lists.newArrayList();

        // 转换结果集
        List<CaseLibraryDTO> result = BeanUtil.batchTransform(CaseLibraryDTO.class, data);

        // 将图片名更换为图片地址
        result = result.stream().map(caseLibraryDTO -> {
            caseLibraryDTO.setFile(LocalResourcesEnum.CASES.getMappingUrl(caseLibraryDTO.getFile()));
            return caseLibraryDTO;
        }).collect(Collectors.toList());
        return result;
    }

    /**
     * 检查创建案例的参数
     *
     * @param createParam 创建参数
     */
    private void checkCreateCaseLibraryParam(CreateCaseLibraryParam createParam) {
        Preconditions.checkNotNull(createParam);
        // 检查行业id是否存在
        checkBusinessIdExist(createParam.getBusinessId());
        // 检查案例标题是否存在
        checkCaseNameExist(null, createParam.getTitle());
    }

    /**
     * 检查修改案例的参数
     *
     * @param updateParam 修改参数
     */
    private void checkUpdateCaseLibraryParam(UpdateCaseLibraryParam updateParam) {
        Preconditions.checkNotNull(updateParam);
        // 检查案例id是否存在
        getCase(updateParam.getId());
        // 检查案例标题是否存在
        checkCaseNameExist(updateParam.getId(), updateParam.getTitle());
    }

    /**
     * 检查案例名称是否存在
     *
     * @param id   案例id
     * @param name 案例标题
     */
    private void checkCaseNameExist(Long id, String name) {
        CaseLibraryExample example = new CaseLibraryExample();
        CaseLibraryExample.Criteria criteria = example.createCriteria();
        criteria.andTitleEqualTo(name);
        criteria.andDeletedEqualTo(false);
        if (id != null) {
            criteria.andIdNotEqualTo(id);
        }
        List<CaseLibrary> caseLibraries = caseLibraryMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(caseLibraries)) {
            throw new BadRequestException("案例名称已存在，请重新添加");
        }
    }

    /**
     * 转换案例随机图标
     *
     * @param caseLibrary 需要转换的数据
     */
    private void convertRandomCaseFile(CaseLibrary caseLibrary) {

        if (StringUtils.isNotBlank(caseLibrary.getFile())) return;

        List<SystemConfig> systemConfigVOS = configService.listConfigByKeys(
                Lists.newArrayList(SystemConfigEnum.CASE_ICON_DEFAULT.getKey())
        );
        if (CollectionUtils.isEmpty(systemConfigVOS)) return;
        caseLibrary.setFile(RandomUtil.randomEle(systemConfigVOS).getKeyValue());
    }

    /**
     * 删除案例
     *
     * @param businessId 行业id
     * @param caseIds    案例id集合
     */
    private void deleteCases(Long businessId, List<Long> caseIds) {
        // 设置删除的对象
        CaseLibrary caseLibrary = new CaseLibrary();
        caseLibrary.setDeleted(true);

        // 设置条件
        CaseLibraryExample example = new CaseLibraryExample();
        CaseLibraryExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        if (businessId != null) {
            criteria.andBusinessIdEqualTo(businessId);
        }
        if (CollectionUtils.isNotEmpty(caseIds)) {
            criteria.andIdIn(caseIds);
        }
        caseLibraryMapper.updateByExampleSelective(caseLibrary, example);
    }

    /**
     * 根据当前人的角色，修改案例表中的点赞数量
     *
     * @param judgeEnum            点赞/取消赞
     * @param caseLibraryDetailDTO 修改的对象
     */
    private void updateCaseStar(JudgeEnum judgeEnum, CaseLibraryDetailDTO caseLibraryDetailDTO) {
        CaseLibrary caseLibrary = BeanUtil.transform(CaseLibrary.class, caseLibraryDetailDTO);
        Long teacherUpdateStarNum = caseLibraryDetailDTO.getTeacherStar() + Long.valueOf(judgeEnum.getOperating());
        Long studentUpdateStarNum = caseLibraryDetailDTO.getStudentStar() + Long.valueOf(judgeEnum.getOperating());
        if (userInfoHolder.isStudent()) {
            caseLibrary.setStudentStar(studentUpdateStarNum);
        }
        if (userInfoHolder.isTeacher()) {
            caseLibrary.setTeacherStar(teacherUpdateStarNum);
        }
        caseLibraryMapper.updateByPrimaryKeySelective(caseLibrary);
    }

    /**
     * 修改点赞记录数据
     *
     * @param judgeEnum 点赞/取消点赞枚举
     * @param caseId    案例id
     */
    private void updateStar(JudgeEnum judgeEnum, Long caseId) {
        if (judgeEnum == JudgeEnum.CANCEL) {
            // 删除点赞记录
            deleteStar(caseId);
        }
        if (judgeEnum == JudgeEnum.LIKE) {
            // 添加点赞记录
            insertStar(caseId);
        }
    }

    /**
     * 当前用户添加点赞记录
     *
     * @param caseId 案例id
     */
    private void insertStar(Long caseId) {
        Star star = new Star();
        star.setCaseId(caseId);
        if (userInfoHolder.isStudent()) {
            star.setStudentStar(1L);
        }
        if (userInfoHolder.isTeacher()) {
            star.setTeacherStar(1L);
        }
        star.setStarUserId(userInfoHolder.getUserId());
        starMapper.insertSelective(star);
    }

    /**
     * 当前用户删除点赞记录
     *
     * @param caseId 案例id
     */
    private void deleteStar(Long caseId) {
        Star star = new Star();
        star.setDeleted(true);

        StarExample example = new StarExample();
        example.createCriteria()
                .andCaseIdEqualTo(caseId)
                .andStarUserIdEqualTo(userInfoHolder.getUserId())
                .andDeletedEqualTo(false);
        starMapper.updateByExampleSelective(star, example);
    }

    /**
     * 删除点赞数
     *
     * @param caseIds 案例id集合
     */
    private void deleteStar(List<Long> caseIds) {
        Star star = new Star();
        star.setDeleted(true);

        StarExample example = new StarExample();
        example.createCriteria().andCaseIdIn(caseIds);
        starMapper.updateByExampleSelective(star, example);
    }

}
